#ifndef HELMETI2C_H
#define HELMETI2C_H

#include "HelmetSystemConfig.h"
#include "HelmetUART.h"
#include <stdio.h>

/**************************************************************************************
	Definitions
**************************************************************************************/
#define FuelGaugeClockFreq			100000
#define FuelGaugeSlaveAddr			0x34
#define FuelGaugeI2Cbus				I2C2
#define W /* write mode */			0x00
#define R /* read mode */			0x01

// Register Memory Locations
#define FUEL_GAUGE_STATUS_REG		0x01
#define FUEL_GAUGE_VOLT_REG			0x0C
#define FUEL_GAUGE_CMD_REG			0xFE
#define FUEL_GAUGE_RARC_REG			0x06
#define FUEL_GAUGE_ACR_REG			0x10

// Commandd Register Commands
#define FGCMD_RECALL_APP_PARAMETERS	0xB4 // takes 2ms ?
#define FGCMD_STORE_APP_PARAMETERS	0x44 // takes 2ms

// Application Parameters Memory Locations
#define FUEL_GAUGE_RSNSP_RAM		0x69
#define FUEL_GAUGE_VCHG_RAM			0x64
#define FUEL_GAUGE_VAE_RAM			0x66
#define FUEL_GAUGE_IMIN_RAM			0x65
#define FUEL_GAUGE_IAE_RAM			0x67
#define FUEL_GAUGE_AC_MSB_RAM		0x62
#define FUEL_GAUGE_AC_LSB_RAM		0x63
#define FUEL_GAUGE_AS_REG			0x14
#define FUEL_GAUGE_FULL40_MSB_RAM	0x6A
#define FUEL_GAUGE_FULL40_LSB_RAM	0x6B

// Application Parameter Dependences
#define FG_RSNSP					200 // Siemens ( 1 / <Rsns> )
#define FG_BATT_FULL				4000 // uVh ( <Batt's Ah> / RSNSP / 6.25uVh )

// Status Register Actions
#define ReadFuelGaugeStatusReg()	ReadFuelGaugeByte(FUEL_GAUGE_STATUS_REG)
#define ClearFuelGaugeStatusReg()	WriteFuelGaugeByte(0x00,FUEL_GAUGE_STATUS_REG)

// 
#define ReadFuelGaugeVoltReg()		ReadFuelGaugeTwoBytes(FUEL_GAUGE_VOLT_REG)
#define ReadFuelGaugeRARCReg()		ReadFuelGaugeByte(FUEL_GAUGE_RARC_REG)

// 
#define WriteFuelGaugeCommand(x)	WriteFuelGaugeByte(x,FUEL_GAUGE_CMD_REG)
#define FuelGaugeRecallAppParams()	WriteFuelGaugeCommand(FGCMD_RECALL_APP_PARAMETERS)
#define FuelGaugeStoreAppParams()	WriteFuelGaugeCommand(FGCMD_STORE_APP_PARAMETERS)
// Sets battery level to FG_BATT_FULL
#define SetBattLevelToFull()		WriteFuelGaugeByte( ((FG_BATT_FULL&0xFF00)>>8)&0x00FF, FUEL_GAUGE_ACR_REG ); \
									WriteFuelGaugeByte( FG_BATT_FULL&0x00FF, FUEL_GAUGE_ACR_REG+0x01 )
// Resets Full40 Register to 100%
#define ResetFull40()				WriteFuelGaugeByte( 0x40, FUEL_GAUGE_FULL40_MSB_RAM ); \
									WriteFuelGaugeByte( 0x0A, FUEL_GAUGE_FULL40_LSB_RAM )

#define FUEL_GAUGE_CHECK_INTERVAL	4

/**************************************************************************************
	Global Variables
**************************************************************************************/
// Main loop control
unsigned int MainCheckFuelGauge = FUEL_GAUGE_CHECK_INTERVAL-1; // check fuel gauge @ start

/**************************************************************************************
	Function Prototypes
**************************************************************************************/
void ConfigFuelGauge(void);
void FuelGaugeInitialSetup(void);
float GetFuelGaugeVinValue(void);
unsigned short int WriteFuelGaugeByte( int data, int maddr );
int ReadFuelGaugeByte( int maddr );
void FuelGaugeSetAppParameter( int data, int caddr );

/**************************************************************************************
	Functions
**************************************************************************************/
void ConfigFuelGauge() {
	// Set the I2C baudrate
    UINT32 actualClock = I2CSetFrequency(FuelGaugeI2Cbus, GetPeripheralClock(), FuelGaugeClockFreq);
    if ( abs(actualClock-FuelGaugeClockFreq) > FuelGaugeClockFreq/10 ) {
        //WriteAtom("Error: I2C1 clock frequency error\r\n");
    }
    // Enable the I2C bus
    I2CEnable(FuelGaugeI2Cbus, TRUE);
    
    // perform initial set-up of fuel gauge (only needs to be done once)
  	FuelGaugeInitialSetup();
  	ResetFull40();
  	SetBattLevelToFull();
    
    // recall App Parameter EEPROM data into shadow RAM
    FuelGaugeRecallAppParams();
}

void FuelGaugeInitialSetup() {
	// Write RSNSP (sense resistor prime) value
    FuelGaugeSetAppParameter( (short int) 200, FUEL_GAUGE_RSNSP_RAM );
    // VCHG (charge voltage) value
    FuelGaugeSetAppParameter( (short int) 167, FUEL_GAUGE_VCHG_RAM );
    // VAE (active empty voltage) value
    FuelGaugeSetAppParameter( (short int) 147, FUEL_GAUGE_VAE_RAM );
    // IMIN (minimum charge current) value
    FuelGaugeSetAppParameter( (short int) 22, FUEL_GAUGE_IMIN_RAM );
    // IAE (active empty current) value
    FuelGaugeSetAppParameter( (unsigned short int) 2, FUEL_GAUGE_IAE_RAM );
    // AC (aging capacity) MSB, LSB
    FuelGaugeSetAppParameter( (FG_BATT_FULL&0xFF00)>>8, FUEL_GAUGE_AC_MSB_RAM );
    FuelGaugeSetAppParameter( (FG_BATT_FULL&0x00FF), FUEL_GAUGE_AC_LSB_RAM ); // 0x0fa0=4000
    // AS (age scalar) ram value
    WriteFuelGaugeByte( (short int) 122, FUEL_GAUGE_AS_REG );
}	

void FuelGaugeSetAppParameter( int data, int caddr ) {
	// write data to shadow RAM
	WriteFuelGaugeByte( data, caddr );
	// copy shadow RAM to EEPROM
	FuelGaugeStoreAppParams();
	// wait >2ms
	int i=300000; // i-nominal is 160000
	while( i>0 ) i--;
}	

float GetFuelGaugeVinValue() {
	int readval = 0;
	float vin = 0.0;
	readval = ReadFuelGaugeTwoBytes( FUEL_GAUGE_VOLT_REG );
	if( readval < 0 ) {
		return -512.00;
	}
	//vin = ( (short int) readval )*0.00015227 + 0.00102605;
	vin = ( (short int)readval )/32*0.00488;
	return vin;
}	

int ReadFuelGaugeByte( int maddr ) {
	// data to return
	int rdata = 0;
	
	// make sure I2C2 is ready
	while( !I2CTransmitterIsReady( FuelGaugeI2Cbus ) );
	
	// READ FORMAT TEMPLATE FOR FUEL GAUGE (SEE DS2782 DATASHEET PG 25-26)
	// S		: Send start condition
	StartI2C2(); IdleI2C2();
	// SAddr W	: Write slave address in write mode
	MasterWriteI2C2( FuelGaugeSlaveAddr << 1 | W ); IdleI2C2();
	// [A]		: return -1 if no ack from fg
	if( !I2CByteWasAcknowledged( FuelGaugeI2Cbus ) ) {
		rdata -= 1;
	}	
	// MAddr	: write memory address to fg
	MasterWriteI2C2( maddr ); IdleI2C2();
	// [A]		: return -1 if no ack from fg
	if( !I2CByteWasAcknowledged( FuelGaugeI2Cbus ) ) {
		rdata -= 2;
	}	
	// Sr		: Send repeat start condition
	RestartI2C2(); IdleI2C2();
	// SAddr	: Write slave address in read mode
	MasterWriteI2C2( FuelGaugeSlaveAddr << 1 | R ); IdleI2C2();
	// [A]		: return -1 if no ack from fg
	if( !I2CByteWasAcknowledged( FuelGaugeI2Cbus ) ) {
		rdata -= 4;
	}	
	// [Data0]	: Read in data value only if no errors
	if( rdata == 0 ) {
		rdata = MasterReadI2C2();
	} else {
		MasterReadI2C2();
	}
	// N		: no ack from master
	NotAckI2C2();
	// P		: generate Stop bit
	StopI2C2(); IdleI2C2();
	
	// return the data read (or error code)
	return rdata;
}

unsigned short int WriteFuelGaugeByte( int data, int maddr ) {
	// return value
	unsigned short int rv=0;
	// make sure I2C2 is ready
	while( !I2CTransmitterIsReady( FuelGaugeI2Cbus ) );
	
	// WRITE FORMAT TEMPLATE FOR FUEL GAUGE (SEE DS2782 DATASHEET PG 25-26)
	// S		: Send start condition
	StartI2C2(); IdleI2C2();
	// SAddr W	: Write slave address in write mode
	MasterWriteI2C2( (FuelGaugeSlaveAddr<<1) | W ); IdleI2C2();
	// [A]		: return -1 if no ack from fg
	if( !I2CByteWasAcknowledged( FuelGaugeI2Cbus ) ) { rv+=1;  }
	// MAddr	: write memory address to fg
	MasterWriteI2C2( maddr ); IdleI2C2();
	// [A]		: return -1 if no ack from fg
	if( !I2CByteWasAcknowledged( FuelGaugeI2Cbus ) ) { rv+=2; }
	// Data0	: write data to fg
	MasterWriteI2C2( data ); IdleI2C2();
	// [A]		: return -1 if no ack from fg
	if( !I2CByteWasAcknowledged( FuelGaugeI2Cbus ) ) { rv+=4; }
	// P		: generate Stop bit
	StopI2C2(); IdleI2C2();
	
	// data written successfully
	return rv; 
}

int ReadFuelGaugeTwoBytes( int maddr ) {
	int rdata = 0; // data to return
	int tdata = 0; // temp data
	
	// make sure I2C2 is ready
	while( !I2CTransmitterIsReady( FuelGaugeI2Cbus ) );
	
	// READ FORMAT TEMPLATE FOR FUEL GAUGE (SEE DS2782 DATASHEET PG 25-26)
	// S		: Send start condition
	StartI2C2(); IdleI2C2();
	// SAddr W	: Write slave address in write mode
	MasterWriteI2C2( FuelGaugeSlaveAddr << 1 | W ); IdleI2C2();
	// [A]		: return -1 if no ack from fg
	if( !I2CByteWasAcknowledged( FuelGaugeI2Cbus ) ) {
		rdata -= 1;
	}	
	// MAddr	: write memory address to fg
	MasterWriteI2C2( maddr ); IdleI2C2();
	// [A]		: return -1 if no ack from fg
	if( !I2CByteWasAcknowledged( FuelGaugeI2Cbus ) ) {
		rdata -= 2;
	}	
	// Sr		: Send repeat start condition
	RestartI2C2(); IdleI2C2();
	// SAddr	: Write slave address in read mode
	MasterWriteI2C2( FuelGaugeSlaveAddr << 1 | R ); IdleI2C2();
	// [A]		: return -1 if no ack from fg
	if( !I2CByteWasAcknowledged( FuelGaugeI2Cbus ) ) {
		rdata -= 4;
	}
	// if no errors ...
	if( rdata == 0 ) {
		// [Data0]	: Read in data byte 1 only if no errors
		rdata = MasterReadI2C2() << 8;
		// A		: ack from master
		AckI2C2(); IdleI2C2();
		// [Data1]	: read in data byte 2 only if no errors
		rdata += MasterReadI2C2();
	} else {
		MasterReadI2C2();
		AckI2C2();
		MasterReadI2C2();
	}
	// N		: no ack from master
	NotAckI2C2();	
	// P		: generate Stop bit
	StopI2C2(); IdleI2C2();
	
	// return the data read (or error code)
	return rdata;
}	

/**************************************************************************************
	Interrupt handling routines
**************************************************************************************/
// Note: Priority 1 (lowest) to 7 (highest)

#endif